\chapter{GNU Regex库用户接口}

GNU Regex库分为GNU、POSIX兼容和BSD兼容3种不同用户界面，本章将对这3种用户接口
进行简要说明。

\section{GNU界面接口函数}

GNU界面接口函数较多，功能划分也较为细致。其优点是搜索时不但会检查匹配，而且会返回
匹配起始位置。另外它还提供一次在两个字符串中进行匹配和搜索的函数，这可以实现跨越
两行的匹配或搜索。但GNU界面接口函数参数较多，使用复杂，并且是GNU独有的，因此与
常规正则表达式语法存在一定兼容性问题。

GNU界面函数共有8个，分别为：

\begin{enumerate}
  \item \cinline{re_set_syntax()}:正则表达式语法设置函数；
  \item \cinline{re_compile_pattern()}:正则表达式编译函数；
  \item \cinline{re_compile_fastmap()}:fastmap正则表达式编译函数；
  \item \cinline{re_search()}:单字符串搜索函数；
  \item \cinline{re_search_2()}:双字符串搜索函数；
  \item \cinline{re_match()}:单字符串匹配函数；
  \item \cinline{re_match_2()}:双字符串匹配函数；
  \item \cinline{re_set_registers()}:匹配寄存器设置函数。
\end{enumerate}

\subsection{设置正则表达式语法}
在GNU Regex中，可以通过\enquote{语法位}的不同组合对使用的
正则表达式语法进行设置。这可以通过直接为\cinline{re_syntax_options}全局
变量赋值的方式实现，也可以通过\cinline{re_set_syntax()}函数进行设置，
其函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    reg_syntax_t re_set_syntax (reg_syntax_t __syntax);
  \end{ccode}
\end{minipage}

该函数用于设置当前使用的正则表达式语法，同时返回旧的语法设置。

形参：
\begin{itemize}
  \item \cinline{__syntax}: 语法位整数，可以用不同位的开关状态(1/0)表示不同
      语法组合，这些语法位可以通过GNU Regex定义的宏常量及这些常量的组合%
      (\cinline{'|'}按位\enquote{或}运算)进行设置，这些宏常量详见附录%
      \ref{gnu-app-syntax-macros}。
\end{itemize}

\subsection{编译正则表达式}
在GNU界面实现正则匹配或搜索的第一步就是将正则表达式编译成正则匹配或搜索
函数能够使用的正则缓存，其函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    const char *re_compile_pattern (const char *__pattern,
             size_t __length, struct re_pattern_buffer *__buffer);
  \end{ccode}
\end{minipage}

函数返回\cinline{NULL}表示编译成功，否则返回\enquote{错误字符串}。

形参：
\begin{description}
  \item \cinline{__pattern}: 指向正则表达式字符串的指针；
  \item \cinline{regex_size}: 正则表达式字符串的长度；
  \item \cinline{__buffer}: 指向正则缓存的指针。
\end{description}

\begin{codebox}{GNU界面正则表达式编译使用范例}
  /*
    reg_pat: 正则表达式
    pat_buf: 正则缓存(匹配模式缓存)
    err_buf: 编译结果字符串
  */
  const char reg_pat[] = "[Ff]oo";
  struct re_pattern_buffer pat_buf;
  const cahr *err_buf;

  // 至少初始化pat_buf的4个成员
  pat_buf.allocated = 0;
  pat_buf.buffer = 0;
  pat_buf.fastmap = 0;
  pat_buf.translate = 0;

  // 设置正则语法
  re_syntax_options = RE_SYNTAX_EGREP;

  // 编译正则表达式
  err_buf = re_compile_pattern(reg_buf, strlen(reg_buf), &pat_buf);
\end{codebox}

\begin{note}
  \begin{enumerate}
    \item 正则缓存在使用结束后，必须用\cinline{regfree()}函数进行释放其占有的
        空间，否则会造成\enquote{内存泄漏}；
    \item 在编译正则表达式之前，至少要初始化\cinline{__buffer}指向的正则缓存
          的\cinline{translate}、\cinline{fastmap}、\cinline{buffer}和%
          \cinline{allocated}这4个成员，当然，也可以根据需要初始化其它成员。
  \end{enumerate}
\end{note}

\subsection{fastmap编译}
当需要在较长的字符串中搜索时，强烈建议使用fastmap方式对正则缓存再次进行编译，
以提高搜索速度，其函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    int re_compile_fastmap (struct re_pattern_buffer *__buffer);
  \end{ccode}
\end{minipage}

函数返回\cinline{0}表示编译成功，返回\cinline{-2}表示发生了内部错误。

形参：
\begin{itemize}
  \item \cinline{__buffer}: 指向正则缓存的指针；
\end{itemize}

需要在使用\cinline{re_compile_pattern()}之前，将正则缓存的fastmap成员初始化为
fastmap(常量)，并仅需一次初始化即可。

\begin{codebox}{fastmap编译使用范例}
  /*
    reg_pat: 正则表达式
    pat_buf: 正则缓存(匹配模式缓存)
    err_buf: 编译结果字符串
    fastmap: fastmap空间
    n: 使用fastmap编译的结果
  */
  const char reg_pat[] = "[Ff]oo";
  struct re_pattern_buffer pat_buf;
  const cahr *err_buf;
  char fastmap[1 << 8];
  int n;

  // 初始化pat_buf结构体
  pat_buf.allocated = 0;
  pat_buf.buffer = 0;
  pat_buf.fastmap = fastmap;
  pat_buf.translate = 0;

  // 设置正则语法
  re_syntax_options = RE_SYNTAX_EGREP;

  // 编译正则表达式
  err_buf = re_compile_pattern(reg_buf, strlen(reg_buf), &pat_buf);

  // 使用fastmap进行编译
  n = re_compile_fastmap(&pat_buf);
\end{codebox}

\subsection{单字符串搜索}
在单一一个字符串中用指定的正则缓存进行搜索，其函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    regoff_t re_search (struct re_pattern_buffer *__buffer,
                        const char *__String, regoff_t __length,
                        regoff_t __start, regoff_t __range,
                        struct re_registers *__regs);
  \end{ccode}
\end{minipage}

函数返回\cinline{-1}表示搜索失败，返回\cinline{-2}表示发生内部错误，
返回\enquote{非负整数}表示匹配字符串的起始位置(有可能是\cinline{0})。

形参：
\begin{description}
  \item \cinline{__buffer}: 指向正则缓存的指针；
  \item \cinline{__String}: 指向待搜索字符串的指针；
  \item \cinline{__length}: 待搜索字符串的长度；
  \item \cinline{__start}: 搜索起始位置；
  \item \cinline{__range}: 搜索范围(从起始位置开始的长度)；
  \item \cinline{__regs}: 指向\cinline{struct re_registers}结构体类型的
      匹配寄存器的指针。
\end{description}

关于匹配寄存器的使用细节，详见附录\ref{gnu-app-registers}。

\begin{note}
  \begin{enumerate}
    \item \cinline{__range}可以是负数，表示从\cinline{__start}开始向前搜索；
    \item 如果\cinline{__start}不在\verb|[0, __length]|之间，则搜索会失败；
    \item 如果传入了匹配寄存器，则在使用后，
        需要调用\cinline{free()}函数删除其\cinline{start}和\cinline{end}成员
        指向的动态内存。
  \end{enumerate}
\end{note}

\begin{codebox}{单字符串搜索使用范例}
  /*
    n: 搜索结果
    s：待搜索字符串指针
    regs: 匹配寄存器
    pat_buf: 正则缓存(匹配模式缓存)
  */
  int n;
  const char *s;
  struct re_registers regs;
  struct re_pattern_buffer pat_buf;

  // 从s的开始位置直到最后进行搜索
  n = re_search(&pat_buf, s, strlen(s), 0, strlen(s), &regs);
\end{codebox}

\subsection{双字符串搜索}
在两个字符串中的搜索与在一个字符串中进行搜索是类似，其区别是可以一次指定两个被
搜索字符串，其函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    regoff_t re_search_2 (struct re_pattern_buffer *__buffer,
                          const char *__string1, regoff_t __length1,
                          const char *__string2, regoff_t __length2,
                          regoff_t __start, regoff_t __range,
                          struct re_registers *__regs,
                          regoff_t __stop);
  \end{ccode}
\end{minipage}

函数返回\cinline{-1}表示搜索失败，返回\cinline{-2}表示发生内部错误，
返回\enquote{非负整数}表示匹配字符串的起始位置(有可能是\cinline{0})。

形参：
\begin{description}
  \item \cinline{__buffer}: 指向正则缓存的指针；
  \item \cinline{__string1}: 指向待搜索字符串1的指针；
  \item \cinline{__length1}: 待搜索字符串1的长度；
  \item \cinline{__string2}: 指向待搜索字符串2的指针；
  \item \cinline{__length2}: 待搜索字符串2  的长度；
  \item \cinline{__start}: 搜索起始位置；
  \item \cinline{__range}: 搜索范围(从起始位置开始的长度)；
  \item \cinline{__regs}: 指向\cinline{struct re_registers}结构体类型的
      匹配寄存器的指针；
  \item \cinline{__stop}: 搜索结束位置。
\end{description}

\begin{note}
  \begin{enumerate}
    \item \cinline{__range}可以是负数，表示从\cinline{__start}开始向前找；
    \item 如果\cinline{__start}不在\verb|[0, __length]|之间，则搜索会失败；
    \item 两个字符串的搜索本质上是将两个字符串合并后进行搜索。
  \end{enumerate}
\end{note}

\begin{codebox}{两字符串搜索使用范例}
  /*
    n: 搜索结果
    s1：待搜索字符串1指针
    s2：待搜索字符串2指针
    regs: 匹配寄存器
    pat_buf: 正则缓存(匹配模式缓存)
  */
  int n;
  const char *s1;
  const char *s2;
  struct re_registers regs;
  struct re_pattern_buffer pat_buf;

  // 从s的开始位置直到最后进行搜索
  n = re_search_2(&pat_buf, s1, strlen(s1), s2, strlen(s2),
                  0, strlen(s1) + strlen(s2), &regs,
                  strlen(s1) + strlen(s2));
\end{codebox}

\subsection{单字符串匹配}
在单一一个字符串中用指定的正则缓存进行匹配的函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    regoff_t re_match(struct re_pattern_buffer *__buffer,
                      const char *__String, regoff_t __length,
                      regoff_t __start,
                      struct re_registers *__regs);
  \end{ccode}
\end{minipage}

函数返回\cinline{-1}表示匹配失败，返回\cinline{-2}表示发生内部错误，
返回\enquote{非负整数}表示匹配字符串的长度。

形参：
\begin{description}
  \item \cinline{__buffer}: 指向正则缓存的指针；
  \item \cinline{__String}: 指向待匹配字符串的指针；
  \item \cinline{__length}: 待匹配字符串的长度；
  \item \cinline{__start}: 匹配起始位置；
  \item \cinline{__regs}: 指向\cinline{struct re_registers}结构体类型的
      匹配寄存器的指针；
\end{description}

\begin{note}
  \begin{enumerate}
    \item 在被匹配字符串中可能含有\cinline{newline}和\cinline{null}。
    \item 如果\cinline{__start}不在\verb|[0, __length]|之间，则匹配会永远失败。
    \item 在GNU Regex库的GNU用户界面中，匹配与搜索是不同的，匹配指的是从头开始，
        如果从头开始没有匹配，即便此后发生了匹配也算是匹配失败。
  \end{enumerate}
\end{note}

\begin{codebox}{单字符串匹配使用范例}
  /*
    n: 匹配结果
    s：待匹配字符串指针
    regs: 匹配寄存器
    pat_buf: 正则缓存(匹配模式缓存)
  */
  int n;
  const char *s;
  struct re_registers regs;
  struct re_pattern_buffer pat_buf;

  // 从s的开始位置直到最后进行匹配
  n = re_match(&pat_buf, s, strlen(s), 0, &regs);
\end{codebox}

\subsection{双字符串匹配}
在两个字符串中的匹配与单个字符串的匹配类似，其函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    regoff_t re_match_2(struct re_pattern_buffer *__buffer,
                        const char *__string1, regoff_t __length1,
                        const char *__string2, regoff_t __length2,
                        regoff_t __start, struct re_registers *__regs,
                        regoff_t __stop);
  \end{ccode}
\end{minipage}

函数返回\cinline{-1}表示匹配失败，返回\cinline{-2}表示发生内部错误，
返回\enquote{非负整数}表示匹配字符串的长度。

形参：
\begin{description}
  \item \cinline{__buffer}: 指向正则缓存的指针；
  \item \cinline{__string1}: 指向待匹配字符串1的指针；
  \item \cinline{__length1}: 待匹配字符串1的长度；
  \item \cinline{__string2}: 指向待匹配字符串2的指针；
  \item \cinline{__length2}: 待匹配字符串2的长度；
  \item \cinline{__start}: 匹配起始位置；
  \item \cinline{__regs}: 指向\cinline{struct re_registers}结构体类型的
      匹配寄存器的指针；
  \item \cinline{__stop}: 匹配结束位置。
\end{description}

\begin{note}
  \begin{enumerate}
    \item 在被匹配字符串中可能含有\cinline{newline}和\cinline{null}。
    \item 如果\cinline{__start}不在\verb|[0, __length]|之间，则匹配会失败。
    % \item 在GNU Regex库的GNU用户界面中匹配与搜索不同，匹配指的是从头开始匹配。
    %     如果没有匹配，即便是此后发生了匹配也算是匹配失败。
  \end{enumerate}
\end{note}

\begin{codebox}{两字符串匹配使用范例}
  /*
    n: 匹配结果
    s1：待匹配字符串1指针
    s2：待匹配字符串2指针
    regs: 匹配寄存器
    pat_buf: 正则缓存(匹配模式缓存)
  */
  int n;
  const char *s1;
  const char *s2;
  struct re_registers regs;
  struct re_pattern_buffer pat_buf;

  // 从s的开始位置直到最后进行匹配
  n = re_match_2(&pat_buf, s1, strlen(s1), s2, strlen(s2),
                  0, &regs, strlen(s1) + strlen(s2));
\end{codebox}

\subsection{匹配寄存器设置}
该函数用于设置匹配寄存器， 其函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    void re_set_registers (struct re_pattern_buffer *__buffer,
                           struct re_registers *__regs,
                           __re_size_t __num_regs,
                           regoff_t *__starts, regoff_t *__ends);
  \end{ccode}
\end{minipage}

形参：
\begin{description}
  \item \cinline{__buffer}: 指向正则缓存的指针；
  \item \cinline{__regs}: 指向\cinline{struct re_registers}结构体类型的
      匹配寄存器的指针；
  \item \cinline{__num_regs}: 匹配寄存器容量(正则分组个数，包括默认分组group 0)；
  \item \cinline{__starts}: 指向记录起始位置的数组的指针；
  \item \cinline{__ends}: 指向记录结束位置的数组的指针。
\end{description}

如果设置了匹配寄存器，则在后续使用\cinline{__buffer}和\cinline{__regs}进行匹配时，
会使用指定的空间记录匹配结果。\cinline{__starts}和\cinline{__ends}必须使用%
\cinline{malloc()}实现内存分配，并且其长度不小于%
\enquote{\cinline{__num_regs * sizeof(regoff_t)}}个字节。

如果为\cinline{__num_regs}传入\cinline{0}，则后续匹配会使用自动申请其成员
start和end指向的数组的空间。

除非调用了此函数，否则第1次搜索或匹配时，会自动分配寄存器存储空间，并且不会
释放旧数据空间。

\section{POSIX兼容接口函数}

POSIX兼容接口函数与GNU接口函数相比，数量较少，并且它无法像GNU接口函数一样，
返回匹配起始位置。但与POSIX界面兼容，是GNU Regex中兼容性最好的API。

与POSIX兼容接口函数有4个，分别为：

\begin{description}
  \item[\cinline{regcomp()}:]正则表达式编译函数
  \item[\cinline{regexec()}:]字符串搜索函数
  \item[\cinline{regerror()}:]错误报告函数
  \item[\cinline{regfree()}:]正则缓存释放函数
\end{description}

\subsection{正则表达式编译}
与GNU接口一样，使用POSIX接口处理正则的第一步也是将正则表达式编译成正则缓存，
其函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    int regcomp (regex_t *_Restrict_ __preg,
                 const char *_Restrict_ __pattern,
                 int __cflags);
  \end{ccode}
\end{minipage}

函数返回\cinline{0}表示编译成功，\enquote{非0}表示编译失败的错误代码。

形参：
\begin{description}
  \item \cinline{__preg}: 指向\cinline{regex_t}结构体类型的正则缓存的指针；
  \item \cinline{__pattern}: 指向需要编译的正则表达式字符串的指针；
  \item \cinline{__cflags}: 正则语法标识。
\end{description}

在此，\cinline{regex_t}类型是\cinline{struct re_pattern_buffer}结构体类型的别名。

\begin{note}
  \begin{enumerate}
    \item \cinline{__cflags}表示正则语法，可以是以下常量或常量的组合%
        (\cinline{'|'}按位\enquote{或}运算)；
      \begin{description}
        \item[\cinline{REG_EXTENDED}:]如果设置为on，则使用POSIX扩展语法，
            否则使用POSIX基础语法；
        \item[\cinline{REG_ICASE}:]如果设置为on，则忽略大小写，否则大小写敏感；
        \item[\cinline{REG_NEWLINE}:]如果设置为on，则\verb|'^'|和\verb|$|不
            匹配字符串中的\cinline{'\n'}换行符，否则则匹配；
        \item[\cinline{REG_NOSUB}:]如果设置为on，则使用\cinline{regexec()}匹配
            时只返回匹配成功与否，不返回正则表达式中各分组匹配结果(包括默认分组
            group 0)。
      \end{description}
    \item 必须在使用结束后，用\cinline{regfree()}函数释放正则缓存，否则会造成%
          \enquote{内存泄漏}。
  \end{enumerate}
\end{note}

\begin{codebox}{POSIX正则表达式编译使用范例}
  /*
    pat_buf: 正则缓存(匹配模式缓存)
    reg_pat: 正则表达式
    cflags: 语法设置代码
    err_code: 编译结果代码
  */
  regex_t pat_buf;
  char reg_pat[] = "[Ff]oo";
  int cflags;
  int err_code;

  // 设置正则语法
  cflags = REG_NEWLINE;

  // 编译正则表达式
  err_code = regcomp(pat_buf, reg_pat, cflags);
\end{codebox}

\subsection{搜索}
POSIX兼容接口的搜索函数无法指定位置开始搜索，只能从起始位置开始搜索。
并且，它只能返回是否成功匹配，并不能返回匹配子字符串的起始位置。 其函数原型为：

\begin{minipage}{0.87\textwidth}
  \begin{ccode}
    int regexec(const regex_t *_Restrict_ __preg,
                const char *_Restrict_ __String, size_t __nmatch,
                regmatch_t __pmatch[_Restrict_arr_ _REGEX_NELTS(__nmatch)],
                int __eflags);
  \end{ccode}
\end{minipage}

函数返回\cinline{0}表示搜索成功，\enquote{非0}表示搜索失败的错误代码。

形参：
\begin{description}
  \item \cinline{__preg}: 指向正则缓存的指针；
  \item \cinline{__String}: 指向待搜索字符串的指针；
  \item \cinline{__nmatch}: 匹配寄存器数组的长度(正则表达式分组，包括默认分组group 0)；
  \item \cinline{__pmatch}: 指向匹配寄存器数组的指针；
  \item \cinline{__eflags}: 搜索方式标志。
\end{description}

\begin{note}
  \begin{enumerate}
    \item \cinline{__eflags}表示搜索方式，可以是以下常量或常量的组合；
      \begin{description}
        \item[\cinline{REG_NOTBOL}:]如果设置为on，则\cinline{'^'}运算符不匹配行首，
            否则匹配行首；
        \item[\cinline{REG_NOTEOL}:]如果设置为on，则\cinline{'$'}运算符不匹配行尾，
            否则匹配行尾；
        \item[\cinline{REG_STARTEND}:]如果设置为on，使用\cinline{__pmatch[0]}%
            记录整体分组group 0匹配结果开始和结束位置。
      \end{description}
    \item 必须在使用结束后，用\cinline{regfree()}函数释放正则缓存，否则会造成%
          \enquote{内存泄漏}。
  \end{enumerate}
\end{note}

\begin{codebox}{POSIX正则表达式搜索使用范例}
  /*
    pat_buf: 正则缓存(匹配模式缓存)
    s: 被搜索的字符串
    eflags: 语法设置代码
    n: 编译结果代码
  */
  regex_t pat_buf;
  char *s;
  int eflags;
  int n;

  // 不设置搜索标识
  eflags = 0;

  // 以忽略记录搜索过程中的匹配信息的方式实现搜索
  n = regexec(pat_buf, s, 0, 0, eflags);
\end{codebox}

\subsection{错误报告}
若在编译或搜索中发现了错误，则可以使用错误报告函数根据错误代码查询错误信息。
其函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    size_t regerror(int __err_code, const regex_t *_Restrict_ __preg,
                    char *_Restrict_ __errbuf, size_t __errbuf_size)
  \end{ccode}
\end{minipage}

函数返回错误信息的长度。

形参：
\begin{description}
  \item \cinline{__err_code}: 错误代码；
  \item \cinline{__preg}: 指向引起错误的正则缓存的指针；
  \item \cinline{__errbuf}: 指向存储错误信息缓存指针；
  \item \cinline{__errbuf_size}: 存储错误信息缓存的容量。
\end{description}
%
\begin{note}
  在不知道错误信息长度时，可以直接为\cinline{__errbuf}传入\cinline{NULL}指针，为%
  \cinline{__errbuf_size}传入\cinline{0}，以从函数返回值得到错误信息长度。
\end{note}

\begin{codebox}{POSIX错误报告使用范例}
  /*
    pat_buf: 正则缓存(匹配模式缓存)
    reg_pat: 正则表达式
    cflags: 语法设置代码
    err_code: 编译结果代码
    err_buf: 错误信息缓存
  */
  regex_t pat_buf;
  int err_code;
  char err_buf[256];
  char reg_pat[] = "[Ff]oo";
  int cflags;

  // 设置正则语法
  cflags = REG_NEWLINE;

  // 编译正则表达式
  err_code = regcomp(&pat_buf, reg_pat, cflags);

  // 响应错误
  if(err_code != 0)
  {
      regerror(err_code, pat_buf, err_buf, sizeof(err_buf));
      printf("Error: %s\n", err_buf);
  }
\end{codebox}

\subsection{内存释放}
正则缓存在使用完后，需要进行释放，否则会造成内存泄漏。为此，GNU Regex为GNU界面
和POSIX界面提供了统一的内存释放接口，其函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    void regfree (regex_t *__preg);
  \end{ccode}
\end{minipage}

形参：
\begin{itemize}
  \item \cinline{__preg}: 指向正则缓存的指针；
\end{itemize}

\begin{codebox}{释放正则缓存使用范例}
  /*
    pat_buf: 正则缓存(匹配模式缓存)
  */
  regex_t pat_buf;

  // 释放缓存
  regfree(&pat_buf);
\end{codebox}
%
% \begin{note}
%   GNU和POSIX兼容的正则表达式的编译缓存在不用时，都要用\cinline{regfree()}进行释放
%   正则缓存。
% \end{note}

\section{BSD兼容函数}

BSD兼容函数是最少的。它只有两个，并且只能检查是否匹配成功，无法确定起始位置，
使用简单。

与BSD兼容的函数有2个，分别为：

\begin{description}
  \item[\cinline{re_comp()}:]正则表达式编译函数
  \item[\cinline{re_exec()}:]字符串搜索函数
\end{description}

\subsection{正则表达式编译}
BSD兼容正则匹配的第一步也是正则表达式的编译。但由于BSD兼容函数使用的
是内部缓存，因此，仅需将正则表达式传入编译函数即可。
其函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    char *re_comp (const char *regex);
  \end{ccode}
\end{minipage}

如果编译成功，则返回\cinline{NULL}， 如果编译错误，则返回\enquote{非空字符串}

形参：
\begin{itemize}
  \item \cinline{__regex}: 指向正则表达式字符串的指针；
\end{itemize}

\begin{note}
  \begin{enumerate}
    \item 可以通过\cinline{re_syntax_option}全局变量设置正则语法
    \item 由于使用了内部正则缓存，所以只能保留最后一次使用的正则缓存
    \item 如果给参数\cinline{regex}传入\cinline{NULL}，则不改变已编译的正则缓存
  \end{enumerate}
\end{note}

\begin{codebox}{BSD正则编译使用范例}
  /*
    reg_buf: 正则表达式
    err_buf: 保存编译结果状态的字符串
  */
  char reg_buf[] = "[Ff]oo";
  const char *err_buf;

  // 设置正则语法
  re_syntax_options = RE_SYNTAX_GREP;

  // 编译正则表达式
  err_buf = re_comp(reg_buf);
\end{codebox}

\subsection{正则搜索}
BSD兼容搜索函数使用的也是内部缓存，因此，仅需将待搜索字符串的指针传入搜索函数即可。
其函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    int re_exec (const char *string);
  \end{ccode}
\end{minipage}

如果搜索成功，则返回\cinline{1}， 如果搜索失败，则返回\cinline{0}。

形参：
\begin{itemize}
  \item \cinline{string}: 指向待搜索字符串的指针；
\end{itemize}

\begin{note}
  本函数会在内部使用GNU的fastmap正则表达式编译功能。
\end{note}

\begin{codebox}{BSD正则编译使用范例}
  /*
    string: 要被\enquote{[Ff]oo}进行搜索的字符串
    n: 搜索结果
  */
  char *string;
  int n;

  // 编译正则表达式
  n = re_exec(string);
\end{codebox}
